/*
* Copyright (c) 2016 sim.com. All Rights Reserved.
*/
package com.cgmnx.admin.web.filter;

import com.cgmnx.admin.biz.rbac.UserBiz;
import com.cgmnx.admin.common.bean.ApiRes;
import com.cgmnx.admin.common.bean.CurrentUserInfo;
import com.cgmnx.admin.common.bean.UserContext;
import com.cgmnx.admin.common.util.EncryptionUtil;
import com.cgmnx.admin.common.util.JacksonMapper;
import com.cgmnx.admin.common.util.WebUtils;
import com.cgmnx.admin.dao.entity.rbac.UserEntity;
import com.cgmnx.admin.model.enums.rbac.UserStatus;
import com.cgmnx.admin.web.CookieUtil;
import com.cgmnx.admin.web.ResponseUtil;
import com.cgmnx.admin.web.model.CookieUser;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Slf4j
@Setter
@Getter
public class BusinessLoginFilter implements Filter {

    private static final long COOKIE_EXPIRED_TIME = TimeUnit.HOURS.toMillis(2);
    private final static String SOURCE_SCAN_VALUE = "scan";
    //静态资源的前缀
    private static final List<String> STATIC_FILE_PREFIX = Lists.newArrayList("/assets/", "/front/");
    @Autowired
    private UserBiz userBiz;
    private String loginUrl;
    /**
     * 通过Spring 注入，在web.xml配置elegatingFilterProxy
     */
    private Set<String> excludeUrlSet;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String uri = httpRequest.getRequestURI();
        //不需要验证的url
        if (!this.isExcludedUri(uri)) {


            // 从cookie获取登录的信息
            CookieUser cookieUser = CookieUtil.getUser(httpRequest);

            //cookie 是否过期
            if (cookieUser == null || isExpired(cookieUser.get_t())) {
                toLogin(ApiRes.returnFail("未登录"), httpRequest, httpResponse);
                return;
            }

            //根据cookie的信息查询当前用户是否存在
            Optional<UserEntity> optional = userBiz.queryByUserId(cookieUser.get_u());

            if (!optional.isPresent()) {
                toLogin(ApiRes.returnFail("用户不存在"), httpRequest, httpResponse);
                return;
            }

            UserEntity entity = optional.get();
            if (entity.getStatus() != UserStatus.ENABLE) {
                toLogin(ApiRes.returnFail("用户无效，请联系管理员"), httpRequest, httpResponse);
                return;
            }

            String encryption = EncryptionUtil.encryptCookie(entity.getUserId(), cookieUser.get_t(), entity.getSalt());

            if (!StringUtils.equals(encryption, cookieUser.get_v())) {
                toLogin(ApiRes.returnFail("用户Cookie信息错误"), httpRequest, httpResponse);
                return;
            }


            CurrentUserInfo build = CurrentUserInfo.builder()
                    .userId(entity.getUserId())
                    .roleList(entity.getRoleList())
                    .userName(entity.getUserName())
                    .ip(WebUtils.getRealIP(httpRequest))
                    .build();

            UserContext.setUserInfo(build);

        }

        chain.doFilter(request, response);
    }

    private void toLogin(ApiRes errorResult, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException {
        if (errorResult != null) {
            if (isXHR(httpRequest)) {
                ResponseUtil.sendJsonNoCache(httpResponse, JacksonMapper.encodeQuietly(errorResult));
            } else {
                httpResponse.sendRedirect(loginUrl);
            }
            return;
        }
    }

    /**
     * 是否过期
     *
     * @param longTime
     * @return true为过期，false为未过期
     */
    private boolean isExpired(long longTime) {
        // 是否过期
        return (System.currentTimeMillis() - longTime > COOKIE_EXPIRED_TIME);
    }

    protected boolean isExcludedUri(String uri) {

        for (String prefix : STATIC_FILE_PREFIX) {

            //如果是静态资源,则直接跳过
            if (StringUtils.startsWith(uri, prefix)) {
                return true;
            }
        }


        if (CollectionUtils.isEmpty(this.excludeUrlSet)) {
            return false;
        }


        if (this.excludeUrlSet.contains(uri)) {
            return true;
        }

        for (String url : this.excludeUrlSet) {

            url = StringUtils.trimToEmpty(url);
            if (url.endsWith("*")) {
                String sub = url.substring(0, url.length() - 1);
                return (uri.startsWith(sub));
            } else {
                return uri.endsWith(url);
            }
        }

        return false;
    }

    private boolean isXHR(HttpServletRequest request) {
        String xRequestWith = request.getHeader("X-Requested-With");
        return StringUtils.isNotBlank(xRequestWith) && StringUtils.equals(xRequestWith, "XMLHttpRequest");
    }

    @Override
    public void destroy() {
        UserContext.release();
    }

}